package com.growthgate.bootcommon.util;

import lombok.AllArgsConstructor;
import lombok.Data;
import net.coobird.thumbnailator.Thumbnails;
import org.jetbrains.annotations.NotNull;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;

/**
 * 图片工具类
 *
 * @author GrowthGate
 * @date 2019/11/22
 */
public class ImageUtils {

    /**
     * 获取分辨率
     *
     * @param image 图片文件
     * @return 分辨率
     * @throws IOException 读写异常-{@link ImageIO#read(File)}
     */
    @NotNull
    public static Resolution getResolution(@NotNull File image) throws IOException {
        BufferedImage bufferedImage = ImageIO.read(image);
        return new Resolution(bufferedImage.getWidth(), bufferedImage.getHeight());
    }

    /**
     * 按图片比例进行缩放，使新的图片宽、高不大于指定值
     *
     * @param image  需要缩放的图片
     * @param width  缩放宽度
     * @param height 缩放高度
     * @return 新图片
     * @throws IOException 读写异常-{@link Thumbnails.Builder#asBufferedImage()}
     */
    @NotNull
    public static BufferedImage scaleAsBufferedImage(@NotNull File image, int width, int height) throws IOException {
        return Thumbnails.of(image).size(width, height).outputQuality(1).asBufferedImage();
    }

    /**
     * 按图片比例进行缩放，使新的图片宽、高不大于指定值
     *
     * @param os     输出流
     * @param image  需要缩放的图片
     * @param width  缩放宽度
     * @param height 缩放高度
     * @throws IOException 读写异常-{@link Thumbnails.Builder#toOutputStream(OutputStream)}
     */
    public static void scaleToOutputStream(@NotNull OutputStream os, @NotNull File image, int width, int height) throws IOException {
        Thumbnails.of(image).size(width, height).outputQuality(1).toOutputStream(os);
    }

    /**
     * 按图片比例进行缩放，使新的图片为宽、高均大于等于指定值的最小图片（作为div背景使用）
     *
     * @param image  需要缩放的图片
     * @param width  缩放宽度
     * @param height 缩放高度
     * @return 新图片
     * @throws IOException 读写异常
     */
    @NotNull
    public static BufferedImage scaleBackgroundAsBufferedImage(@NotNull File image, int width, int height) throws IOException {
        Resolution resolution = generateBackgroundResolution(image, width, height);
        return scaleAsBufferedImage(image, resolution.getWidth(), resolution.getHeight());
    }

    /**
     * 按图片比例进行缩放，使新的图片宽、高不大于指定值
     *
     * @param os     输出流
     * @param image  需要缩放的图片
     * @param width  缩放宽度
     * @param height 缩放高度
     * @throws IOException 读写异常
     */
    public static void scaleBackgroundToOutputStream(@NotNull OutputStream os, @NotNull File image, int width, int height) throws IOException {
        Resolution resolution = generateBackgroundResolution(image, width, height);
        scaleToOutputStream(os, image, resolution.getWidth(), resolution.getHeight());
    }

    /**
     * 生成背景图宽高
     *
     * @param image  图片文件
     * @param width  最小宽度
     * @param height 最小高度
     * @return 最终分辨率
     * @throws IOException 读写异常
     */
    @NotNull
    private static Resolution generateBackgroundResolution(@NotNull File image, int width, int height) throws IOException {
        // 获取图片宽高
        Resolution resolution = getResolution(image);
        BigDecimal imgWidth = BigDecimal.valueOf(resolution.getWidth());
        BigDecimal imgHeight = BigDecimal.valueOf(resolution.getHeight());
        // 获取图片调整至指定宽高时需要缩放的比例
        BigDecimal widthRatio = BigDecimal.valueOf(width).divide(imgWidth, 10, BigDecimal.ROUND_HALF_UP);
        BigDecimal heightRatio = BigDecimal.valueOf(height).divide(imgHeight, 10, BigDecimal.ROUND_HALF_UP);
        // 获取比例较大值，确保缩略图最终宽高一定大于等于指定值
        BigDecimal maxRatio = widthRatio.max(heightRatio);
        // 获取缩略图宽高并生成缩略图
        int finalWidth = imgWidth.multiply(maxRatio).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
        int finalHeight = imgHeight.multiply(maxRatio).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
        return new Resolution(finalWidth, finalHeight);
    }

    @Data
    @AllArgsConstructor
    public static class Resolution {

        private int width;

        private int height;

    }

}